package com.health.medicine.service.impl;


import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.health.api.client.UserClient;
import com.health.api.client.WareHouseClient;
import com.health.api.model.WareHouseItemEnums;
import com.health.api.model.hospital.GetHospitalInfoRequest;
import com.health.api.model.hospital.HospitalVO;
import com.health.api.model.transporter.AddWareHouseItemRequest;
import com.health.api.model.transporter.TransporterRegisterRequest;
import com.health.common.auth.service.TokenService;
import com.health.common.common.ErrorCode;
import com.health.common.exception.BusinessException;
import com.health.common.model.user.LoginUser;
import com.health.common.model.vo.UserKeyVO;
import com.health.common.service.util.SDKUtils;
import com.health.medicine.mapper.TransportUnitMapper;
import com.health.medicine.model.dto.medicine.TransportGoodsRequest;
import com.health.medicine.model.dto.transporter.TransportGoodsArrivedRequest;
import com.health.medicine.model.dto.transporter.TransportVehiclesRequest;
import com.health.medicine.model.entity.MedicineInfo;
import com.health.medicine.model.entity.TransportRecords;
import com.health.medicine.model.entity.TransportUnit;
import com.health.medicine.model.entity.TransportUnitVehicles;
import com.health.medicine.model.enums.TransportStatus;
import com.health.medicine.service.MedicineInfoService;
import com.health.medicine.service.TransportrecordsService;
import com.health.medicine.service.TransportunitService;
import com.health.medicine.service.TransportunitvehiclesService;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.fisco.bcos.sdk.v3.codec.ContractCodecException;
import org.fisco.bcos.sdk.v3.codec.datatypes.Int;
import org.fisco.bcos.sdk.v3.transaction.model.exception.TransactionBaseException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

import static com.health.common.constant.ContractConstants.*;

/**
* @author zhexueqi
* @description 针对表【TransportUnit(运输单位信息表)】的数据库操作Service实现
* @createDate 2024-08-30 15:46:19
*/
@Service
@Slf4j
public class TransportunitServiceImpl extends ServiceImpl<TransportUnitMapper, TransportUnit>
    implements TransportunitService {

    @Resource
    private SDKUtils sdkUtils;

    @Value("${system.contract.contractName}")
    private String CONTRACT_NAME;

    @Value("${system.contract.address}")
    private String CONTRACT_ADDRESS;

    @Resource
    private TransportrecordsService transportrecordsService;

    @Resource
    private TransportunitvehiclesService transportunitvehiclesService;

    @Resource
    private TokenService tokenService;

    @Resource
    private WareHouseClient wareHouseClient;

    @Resource
    private UserClient userClient;

    @Resource
    private MedicineInfoService medicineInfoService;
    @Override
    public Boolean createTransporterToMysql(TransporterRegisterRequest transactionRegisterRequest) {
        TransportUnit transportUnit = new TransportUnit();
        BeanUtil.copyProperties(transactionRegisterRequest,transportUnit);
        boolean save = this.save(transportUnit);
        if (!save){
            throw new BusinessException(ErrorCode.SQL_ERROR);
        }
        return true;
    }

    @Override
    public void createTransporter(UserKeyVO userKeyVO, String userAccount) throws TransactionBaseException, ContractCodecException {
        QueryWrapper<TransportUnit> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("transport_account",userAccount);
        TransportUnit transportUnit = this.getOne(queryWrapper);
        if (transportUnit == null){
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"用户不存在");
        }
        List<Object> funcParams = new ArrayList<>();
        funcParams.add(transportUnit.getName());
        funcParams.add(transportUnit.getContactPhone());
        funcParams.add(transportUnit.getAvailableVehicles().toString());

        // 调用合约方法，添加运输商信息
        sdkUtils.sendTransaction(CONTRACT_NAME, CONTRACT_ADDRESS, ADD_TRANSPORTER,funcParams,userKeyVO.getPrivateKey());
    }

    /**
     * 运输货物
     *
     * @param transportGoodsRequest 货物运输请求对象，包含运输货物的相关信息
     * @return 如果运输操作成功，则返回true；否则，抛出业务异常
     * @throws BusinessException 如果数据库保存操作失败，则抛出业务异常，错误代码为SQL_ERROR
     *
     * 此方法负责根据提供的运输货物请求执行货物的运输操作它涉及到创建运输记录，
     * 设置运输类型和状态，并最终保存这些记录如果保存操作失败，则抛出业务异常
     */
    @Override
    public Boolean transportGoods(TransportGoodsRequest transportGoodsRequest) throws TransactionBaseException, ContractCodecException {
        // 创建一个新的运输记录对象
        TransportRecords transportRecords = new TransportRecords();
        // 将运输货物请求对象的属性复制到运输记录对象中
        BeanUtil.copyProperties(transportGoodsRequest,transportRecords);
        // 设置运输记录的状态为运输中
        transportRecords.setStatus(TransportStatus.TRANSPORTING);

        //向区块链上添加运输记录
        List<Object> funcParams = new ArrayList<>();
        funcParams.add(transportRecords.getTraceId());
        //获取当前时间戳
        long timestamp = System.currentTimeMillis();
        //转为yyyy-MM-dd HH:mm:ss格式
        String time = new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(timestamp);
        String trackingInfo = String.format("%s,%s,%s,%s,%s",transportRecords.getTransportUnitId(),transportRecords.getVehicleId(),transportRecords.getTransportType(),transportRecords.getStartLocation(),time);
        funcParams.add(trackingInfo);

        // 调用合约方法，添加运输记录
        sdkUtils.sendTransaction(CONTRACT_NAME, CONTRACT_ADDRESS, ADD_TRANS_PORT_INFO,funcParams,transportGoodsRequest.getPrivateKey());

        // 使用运输记录服务保存运输记录
        boolean isUpdateSuccess = transportrecordsService.updateById(transportRecords);
        // 如果保存失败，则抛出业务异常
        if (!isUpdateSuccess){
            throw new BusinessException(ErrorCode.SQL_ERROR);
        }
        // 返回true，表示运输操作成功
        return true;
    }

    @Override
    public Boolean createVehicle(TransportVehiclesRequest transportVehiclesRequest) {
        // 创建一个新的运输车辆对象
        TransportUnitVehicles transportUnitVehicles = new TransportUnitVehicles();
        BeanUtil.copyProperties(transportVehiclesRequest,transportUnitVehicles);
        boolean save = transportunitvehiclesService.save(transportUnitVehicles);
        if (!save){
            throw new BusinessException(ErrorCode.SQL_ERROR);
        }
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean transportGoodsArrived(TransportGoodsArrivedRequest transportGoodsArrivedRequest) throws BusinessException {
        Long traceCode = transportGoodsArrivedRequest.getTraceCode();
        String privateKey = transportGoodsArrivedRequest.getPrivateKey();

        // 调用区块链SDK更新状态
        updateBlockchainStatus(traceCode, privateKey);

        // 更新运输记录状态为到达目的地
        TransportRecords transportRecords = updateTransportRecordStatus(traceCode);

        // 调用仓库服务，添加货物到医院中
        addWareHouseItem(traceCode,transportRecords.getTransportQuantity());

        return true;
    }

    private void updateBlockchainStatus(Long traceCode, String privateKey) throws BusinessException {
        List<Object> funcParams = new ArrayList<>();
        funcParams.add(traceCode);
        try {
            sdkUtils.sendTransaction(CONTRACT_NAME, CONTRACT_ADDRESS, SET_DRUG_STATUS, funcParams, privateKey);
        } catch (Exception e) {
            throw new BusinessException(ErrorCode.CONTRACT_ERROR, "区块链操作失败: " + e.getMessage());
        }
    }

    private TransportRecords updateTransportRecordStatus(Long traceCode) throws BusinessException {
        QueryWrapper<TransportRecords> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("trace_id", traceCode);
        TransportRecords transportRecords = transportrecordsService.getOne(queryWrapper);
        if (transportRecords == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "运输记录不存在");
        }
        transportRecords.setArrivalTime(LocalDateTime.now());
        transportRecords.setStatus(TransportStatus.COMPLETED);
        boolean update = transportrecordsService.updateById(transportRecords);
        if (!update) {
            throw new BusinessException(ErrorCode.SQL_ERROR, "更新运输记录失败");
        }
        return transportRecords;
    }

    private void addWareHouseItem(Long traceCode, Integer quantity) throws BusinessException {
        // 通过溯源码查询药品信息
        MedicineInfo medicineInfo = medicineInfoService.getById(traceCode);
        if (medicineInfo == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "药品信息不存在");
        }

        // 查询医院信息
        GetHospitalInfoRequest getHospitalInfoRequest = new GetHospitalInfoRequest();
        getHospitalInfoRequest.setHospitalAddress(medicineInfo.getReceiverAddress());
        HospitalVO hospitalInfo = userClient.getHospitalInfo(getHospitalInfoRequest);
        if (hospitalInfo == null) {
            throw new BusinessException(ErrorCode.HOSPITAL_NOT_EXIST, "医院信息不存在");
        }

        // 构建添加仓库物品请求
        AddWareHouseItemRequest addWareHouseItemRequest = new AddWareHouseItemRequest();
        addWareHouseItemRequest.setTraceCode(traceCode);
        addWareHouseItemRequest.setItemName(medicineInfo.getDrugName());
        addWareHouseItemRequest.setItemCategory(WareHouseItemEnums.Medicine);
        addWareHouseItemRequest.setItemQuantity(quantity);
        addWareHouseItemRequest.setUnit(medicineInfo.getDrugUnit());
        addWareHouseItemRequest.setExpireDate(medicineInfo.getExpireTime());
        addWareHouseItemRequest.setHospitalId(Long.valueOf(hospitalInfo.getId()));

        // 调用仓库服务，添加货物到医院中
        wareHouseClient.addWareHouseItem(addWareHouseItemRequest);
    }


    @Override
    public Page<TransportRecords> getTransportGoods(int pageNum, int pageSize, HttpServletRequest request) {
        TransportUnit transportUnit = getTransportUnit(request);
        if (pageNum <=0 || pageSize <= 0){
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"页码或页大小不能为空");
        }
        QueryWrapper<TransportRecords> queryWrapper1 = new QueryWrapper<>();
        queryWrapper1.eq("transport_unit_id",transportUnit.getTransportUnitId());
        queryWrapper1.eq("status", TransportStatus.PENDING);
        return transportrecordsService.page(new Page<>(pageNum, pageSize), queryWrapper1);
    }

    private TransportUnit getTransportUnit(HttpServletRequest request) {
        LoginUser loginUser = tokenService.getLoginUser(request);
        String userAccount = loginUser.getUserAccount();
        QueryWrapper<TransportUnit> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("transport_account",userAccount);
        TransportUnit transportUnit = this.getOne(queryWrapper);
        if (transportUnit == null){
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"用户不存在");
        }
        return transportUnit;
    }

    @Override
    public Page<TransportUnitVehicles> getTransportVehicles(int pageNum, int pageSize, HttpServletRequest request) {
        TransportUnit transportUnit = getTransportUnit(request);

        Long transportUnitId = transportUnit.getTransportUnitId();
        if (pageNum <=0 || pageSize <= 0){
            throw new BusinessException(ErrorCode.PARAMS_ERROR,"页码或页大小不能为空");
        }
        QueryWrapper<TransportUnitVehicles> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("transport_unit_id",transportUnitId);
        return transportunitvehiclesService.page(new Page<>(pageNum, pageSize), queryWrapper);
    }


}




